package com.example.codereader;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import android.Manifest;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.net.Uri;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
import android.widget.Toast;

import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.FormatException;
import com.google.zxing.NotFoundException;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.oned.EAN13Reader;
import com.theartofdev.edmodo.cropper.CropImage;
import com.theartofdev.edmodo.cropper.CropImageView;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.Map;

public class MainActivity extends AppCompatActivity {

    protected final int SCAN_REQUEST_CODE = 200;
    protected final int SELECT_IMAGE_REQUEST_CODE = 201;
    protected final int PERMS_REQUEST_CODE = 202;

    private CodeCanvas codeCanvas;
    private ImageView img_load;
    private EditText et_input;
    private TextView tx_out;

    private String inputStr = "";
    private String imgStr = "";

    private View.OnClickListener onClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.bt_selimg:
                    //  选择识别方式
                    PopupMenu popup = new PopupMenu(MainActivity.this, v);//第二个参数是绑定的那个view
                    //获取菜单填充器
                    MenuInflater inflater = popup.getMenuInflater();
                    //填充菜单
                    inflater.inflate(R.menu.main_menu, popup.getMenu());
                    //绑定菜单项的点击事件
                    popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                        @Override
                        public boolean onMenuItemClick(MenuItem item) {
                            switch (item.getItemId()) {
                                case R.id.openCamera:
                                    // TODO 打开相机拍照 获取uri
                                    break;
                                case R.id.selectImg:
                                    // start picker to get image for cropping and then use the image in cropping activity
                                    CropImage.activity()
                                            .setActivityTitle("选择图片识别")
                                            .setGuidelines(CropImageView.Guidelines.ON)
                                            .start(MainActivity.this);
                                    break;
                                default:
                                    break;
                            }
                            return false;
                        }
                    });
                    //显示(这一行代码不要忘记了)
                    popup.show();
                    break;
                case R.id.bt_draw:
                    inputStr = et_input.getText().toString();
                    if (inputStr.length() == 10) {
                        codeCanvas.SetBarCode(MyEAN.Encode(inputStr));
                    } else {
                        showToast("请输入10位数字!");
                    }
                    break;
                case R.id.bt_rebuild:
                    if (imgStr.length() == 10) {
                        codeCanvas.SetBarCode(MyEAN.Encode(imgStr));
                    } else {
                        showToast("请选择图片或扫码!");
                    }
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        String[] permissions = new String[]{Manifest.permission.
                WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA};
        requestPermissions(permissions, PERMS_REQUEST_CODE);

        DisplayMetrics metric = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metric);
        int width = metric.widthPixels;     // 屏幕宽度（像素）
        int height = metric.heightPixels;   // 屏幕高度（像素）
        float density = metric.density;      // 屏幕密度（0.75 / 1.0 / 1.5）
        int densityDpi = metric.densityDpi;

        codeCanvas = findViewById(R.id.code_canvas);
        codeCanvas.setUnitWidth(6);
        img_load = findViewById(R.id.img_load);
        et_input = findViewById(R.id.et_input);
        tx_out = findViewById(R.id.tx_out);

        findViewById(R.id.bt_selimg).setOnClickListener(onClickListener);
        findViewById(R.id.bt_draw).setOnClickListener(onClickListener);
        findViewById(R.id.bt_rebuild).setOnClickListener(onClickListener);

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) {
            CropImage.ActivityResult result = CropImage.getActivityResult(data);
            if (resultCode == RESULT_OK) {
                assert result != null;
//                img_load.setImageURI(result.getUri());
                img_load.setImageBitmap(GrayProcessor(result.getUri()));
                String srcRes = BarReader(result.getUri());
                showToast("从图库选择的图片识别结果:" + srcRes);
                tx_out.setText(srcRes);
            } else if (resultCode == CropImage.CROP_IMAGE_ACTIVITY_RESULT_ERROR_CODE) {
                Exception error = result.getError();
            }
        }
    }

    /**
     * 灰度处理
     *
     * @param uri
     * @return 返回ARGB_8888的Bitmap
     */
    public Bitmap GrayProcessor(Uri uri) {
        Bitmap srcBmp = BitmapFactory.decodeFile(uri.getPath(), null);
        if (srcBmp == null) return null;
        Bitmap bmp = compressBmp(srcBmp);
        Bitmap bitmapNew = bmp.copy(Bitmap.Config.ARGB_8888, true);
        int width = bitmapNew.getWidth();
        int height = bitmapNew.getHeight();
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                int pixel = bitmapNew.getPixel(i, j);
                int a = pixel & 0xff000000;
                int r = (pixel >> 16) & 0xff;
                int g = (pixel >> 8) & 0xff;
                int b = pixel & 0xff;
                int gray = (int) ((float) r * 0.3 + (float) g * 0.59 + (float) b * 0.11);
                int col = a | (gray << 16) | (gray << 8) | gray;
                bitmapNew.setPixel(i, j, col);
            }
        }
        return bitmapNew;
    }

    private boolean is_black(int col) {
        int b = col & 0xff;
        return b < 25;
    }

    private boolean is_void(int col) {
        int b = col & 0xff;
        return b >= 240;
    }

    private boolean is_about(int a, int b) {
        return a - b < 10;
    }

    /**
     * 处理灰度图像，找出序列
     *
     * @param grayImg 一定要是ARGB_8888的Bitmap
     * @return
     */
    public ArrayList<String> GetOrgCodeFromGrayImg(Bitmap grayImg) {
        ArrayList<String> ret = new ArrayList<>();
        int width = grayImg.getWidth();
        int height = grayImg.getHeight();
        int sample = height / 10;
        int constantBlack = 0;
        int constantVoid = 0;
        ArrayList<Integer> raw = new ArrayList<>();
        // 正扫
        for (int j = 0; j < height; j += sample) {
            for (int i = 0; i < width; i++) {
                int curp = grayImg.getPixel(i, j);
                if (is_black(curp)) {
                    constantBlack++;
                } else if (constantBlack != 0) {
                    raw.add(constantBlack);
                    constantBlack = 0;
                }
                if (is_void(curp)) {
                    constantVoid++;
                } else if (constantVoid != 0) {
                    raw.add(-constantVoid);
                    constantVoid = 0;
                }
            }
        }

        // 用来匹配
        int matchs[] = new int[4];
        for (int i = 0; i < raw.size(); i++) {
            //
            for (int j = 0; j < 3; j++) {
                matchs[j] = raw.get(i + j);
            }
            if (is_about(matchs[0], matchs[1]) && is_about(matchs[1], matchs[2])) {
                // 是起始符
            }
        }

        return ret;
    }

    public String BarReader(Uri uri) {
        Bitmap srcBmp = BitmapFactory.decodeFile(uri.getPath(), null);
        if (srcBmp == null) return "Image Error";
        Bitmap bmp = compressBmp(srcBmp);
        int width = bmp.getWidth();//图片宽度
        int height = bmp.getHeight();//图片高度
        int[] pixels = new int[width * height];
        bmp.getPixels(pixels, 0, width, 0, 0, width, height);
        Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
        hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);//优化精度
        hints.put(DecodeHintType.CHARACTER_SET, "utf-8");//解码设置编码方式为：utf-8
        try {
            Result res = new EAN13Reader().decode(new BinaryBitmap(
                    new HybridBinarizer(
                            new RGBLuminanceSource(width, height, pixels)
                    )
            ), hints);
            String resStr = res.getText();
            resStr = resStr.substring(2, 12);
            imgStr = resStr;
            ArrayList<String> resAr = MyEAN.EncodeToList(resStr);
            System.out.println("resAr size: " + resAr.size());
            return MyEAN.Decode(resAr.toArray(new String[0]));
        } catch (NotFoundException | FormatException e) {
            e.printStackTrace();
        }
        return "Failed";
    }

    /**
     * 压缩图片，避免识别时报错
     *
     * @param image bmp
     * @return
     */
    private static Bitmap compressBmp(Bitmap image) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        if (baos.toByteArray().length / 1024 > 1024) {//判断如果图片大于1M,进行压缩避免在生成图片（BitmapFactory.decodeStream）时溢出
            baos.reset();//重置baos即清空baos
            image.compress(Bitmap.CompressFormat.JPEG, 50, baos);//这里压缩50%，把压缩后的数据存放到baos中
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        //开始读入图片，此时把options.inJustDecodeBounds 设回true了
        newOpts.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
        newOpts.inJustDecodeBounds = false;
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        //现在主流手机比较多是800*480分辨率，所以高和宽我们设置为
        float hh = 400f;//这里设置高度为800f
        float ww = 400f;//这里设置宽度为480f
        //缩放比。由于是固定比例缩放，只用高或者宽其中一个数据进行计算即可
        int be = 1;//be=1表示不缩放
        if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
            be = (int) (newOpts.outWidth / ww);
        } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
            be = (int) (newOpts.outHeight / hh);
        }
        if (be <= 0)
            be = 1;
        newOpts.inSampleSize = be;//设置缩放比例
        //重新读入图片，注意此时已经把options.inJustDecodeBounds 设回false了
        isBm = new ByteArrayInputStream(baos.toByteArray());
        bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
        return compressImage(bitmap);//压缩好比例大小后再进行质量压缩
    }

    //质量压缩方法
    private static Bitmap compressImage(Bitmap image) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
        int options = 100;
        while (baos.toByteArray().length / 1024 > 100) { //循环判断如果压缩后图片是否大于100kb,大于继续压缩
            baos.reset();//重置baos即清空baos
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%，把压缩后的数据存放到baos中
            options -= 10;//每次都减少10
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片
        return bitmap;
    }

    private void showToast(String str) {
        Toast.makeText(MainActivity.this, str, Toast.LENGTH_LONG).show();
    }
}
